home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / p063b9s.zip / UNIT / TICK.PAS < prev    next >
Pascal/Delphi Source File  |  1996-08-15  |  30KB  |  898 lines

  1. UNIT Tick;
  2. {╔══════════════════════════════════════════════════════════════════════════╗}
  3. {║ Tick processor                                Last changed: 15.08.96  SA ║}
  4. {║                                                                          ║}
  5. {║                         (C) Copyright 1989-96 by                         ║}
  6. {║       Dan Wulff, Jens Sandalgaard, Steen Christensen & S¢ren Ager        ║}
  7. {║                                                                          ║}
  8. {║ This source may not be given to anybody, without the written permission  ║}
  9. {║ from The Portal Team.                                                    ║}
  10. {╚══════════════════════════════════════════════════════════════════════════╝}
  11. {$I POPDEFS.INC}
  12.  
  13. INTERFACE
  14.  
  15. USES Use32, Dos;
  16.  
  17. PROCEDURE ProcessTicks;
  18. PROCEDURE Hatch(CONST FName: PathStr; CONST Description: STRING);
  19.  
  20. IMPLEMENTATION
  21.  
  22. USES OpString, OpDos, OpDate, OpPick, OpCrt, OpWindow, OpCmd, OpFrame, OpRoot,
  23.      OproUtil, InterCom, StrUtil, LogFile, FileUtil, Send2Utl, MailUtil,
  24.      OutUtil, Input, AreaMisc, NetFile, Util, ArcView, UnixDate, SimpDB,
  25.      Opus_173, Globals, FuncSrvr, PoPTypes;
  26.  
  27. TYPE
  28.   PTickMsg = ^TTickMsg;
  29.   TTickMsg = RECORD
  30.                NumLines : Byte;
  31.                Line     : Array[1..10] OF S80;
  32.              END;
  33.  
  34.   PTickFile = ^TTickFile;
  35.   TTickFile = RECORD
  36.     Area     : S20;
  37.     Origin   : S20;
  38.     From     : TFidoAddress;
  39.     FileName : S12;
  40.     Desc     : String;
  41.     CRC      : LongInt;
  42.     Replaces : S12;
  43.     NumPath  : Byte;
  44.     Path     : Array[1..20] Of String;
  45.     NumSeenBy: Byte;
  46.     SeenBy   : SendToTabType;
  47.     Password : S20;
  48.   END;
  49.  
  50.   TTickAreaPickList = OBJECT(PickList)
  51.     TickFile : PNetFile;
  52.  
  53.     constructor Init(VAR ATickFile: TNetFile);
  54.     procedure ItemString(Item: Word; Mode: pkMode; var IType: pkItemType; var IString: String); virtual;
  55.   END;
  56.  
  57. VAR
  58.   TickFileRec    : PTickFile;
  59.   TickAreaRec    : PTickArea;
  60. {
  61.   TickLetterPath : PathStr;
  62.   TickMsgPtr     : Array[1..3] OF PTickMsg;
  63. }
  64.  
  65.  
  66.   constructor TTickAreaPickList.Init(VAR ATickFile: TNetFile);
  67.   begin
  68.     TickFile:=@ATickFile;
  69.     InitAbstract(23, 3, 57, ScreenHeight-1, Cfg.Color[3], DefWindowOptions or WBordered,
  70.                  22, TickFile^.FileSize, PickVertical, SingleChoice);
  71.     IF Cfg.Screen.ExplodingWin THEN EnableExplosions(10);
  72.     SetSearchMode(PickStringSearch);
  73.     SetPadSize(1,1);
  74.     Wframe.AddHeader(' Tick Areas ',heTC);
  75.     AddMoreHeader(' More   ',HeBR,#24,#25,'',7,8,0);
  76.   END;
  77.  
  78.   procedure TTickAreaPickList.ItemString(Item: Word; Mode: pkMode; var IType: pkItemType; var IString: String);
  79.   VAR
  80.     ta: TTickArea;
  81.   BEGIN
  82.     IString:='';
  83.     IF TickFile^.FileSize>=Item-1 THEN
  84.     BEGIN
  85.       TickFile^.GetRec(Ta, Item-1, NoKeep, Wait);
  86.       IF TickFile^.IoResult=0 THEN IString:=Ta.AreaName;
  87.     END;
  88.   end;
  89.  
  90.   FUNCTION StripDosChars(Area: S20): S20;
  91.   VAR
  92.     i : Byte;
  93.   BEGIN
  94.     i:=1;
  95.     WHILE i<=Length(Area) DO
  96.       IF Area[i] IN ['.',':','\'] THEN Delete(Area, i, 1) ELSE Inc(i);
  97.     StripDosChars:=Area;
  98.   END;
  99.  
  100.  
  101.   FUNCTION Adr2Str(CONST Adr: TFidoAddress): S20;
  102.   VAR
  103.     s : S20;
  104.   BEGIN
  105.     s:=Address2Str(Adr);
  106.     IF Adr.Point=0 THEN s:=Copy(s,1,Pos('.',s)-1);
  107.     Adr2Str:=s;
  108.   END;
  109.  
  110.   FUNCTION FindTickArea(VAR TickFile: TNetFile; CONST AreaName: S20): Boolean;
  111.   VAR
  112.     Found : Boolean;
  113.   BEGIN
  114.     TickFile.Seek(0);
  115.     Found:=False;
  116.     WHILE Not Found And Not TickFile.EoF DO
  117.     BEGIN
  118.       TickFile.Read(TickAreaRec^,NoKeep,Wait);
  119.       Found:=StUpCase(TickAreaRec^.AreaName)=AreaName;
  120.     END;
  121.     FindTickArea:=Found;
  122.   END;
  123.  
  124.   FUNCTION CheckGetFrom(CONST Adr: TFidoAddress): Byte;
  125.   VAR
  126.     Num,i : Byte;
  127.     Found: Boolean;
  128.     GetFromTab : SendToTabType;
  129.   BEGIN
  130.     ReadSendTo(TickAreaRec^.GetFrom, GetFromTab, Num);
  131.     i:=0; Found:=False;
  132.     WHILE (i<=Num) And Not Found DO
  133.     BEGIN
  134.       Inc(i);
  135.       Found:=CmpAdr(GetFromTab[i],Adr);
  136.     END;
  137.     IF Not Found THEN i:=0;
  138.     CheckGetFrom:=i;
  139.   END;
  140.  
  141.   FUNCTION Tick2Buffer(CONST TickName: S12; CONST NodeStat: TNodeStat): Boolean;
  142.   VAR
  143.     t : PBufTextFile;
  144.     s, Rest : String;
  145.     ok: Integer;
  146.     isBad : Boolean;
  147.  
  148.     PROCEDURE BadTic(CONST s: String);
  149.     BEGIN
  150.       AddLog('!','Error in TIC line: "'+s+'"');
  151.       isBad:=True;
  152.     END;
  153.  
  154.     FUNCTION Token(CONST s: String; VAR Rest: String): Byte;
  155.     VAR
  156.       KeyWord : S10;
  157.     BEGIN
  158.       IF Pos(' ',s)>0 THEN
  159.       BEGIN
  160.         KeyWord:='*'+StUpCase(Copy(s, 1, Pos(' ', s)-1))+'*';
  161.         Rest:=Trim(Copy(s, Pos(' ', s)+1, Length(s)-Pos(' ',s)));
  162.         Token:=Pos(KeyWord, '*AREA*ORIGIN*FROM*FILE*DESC*CRC*REPLACES*PATH*SEENBY*PW*');
  163.       END ELSE
  164.         Token:=0;
  165.     END;
  166.  
  167.   BEGIN
  168.     AddLog(' ','Reading '+TickName);
  169.     FillChar(TickFileRec^, SizeOf(TickFileRec^), 0);
  170.     New(t, Init(Cfg.Inbound[NodeStat]+TickName, SOpenRead, 2048));
  171.     IF t<>NIL THEN
  172.     BEGIN
  173.       isBad:=False;
  174.       REPEAT
  175.         t^.ReadLn(s);
  176.         CASE Token(s, Rest) OF
  177.            0 : ;
  178.            1 : TickFileRec^.Area:=StUpCase(Rest);
  179.            6 : TickFileRec^.Origin:=Rest;
  180.           13 : IF Not GetAdressFromStr(Rest, TickFileRec^.From) THEN BadTic(s);
  181.           18 : TickFileRec^.FileName:=Rest;
  182.           23 : TickFileRec^.Desc:=Rest;
  183.           28 : BEGIN
  184.                  Val('$'+Rest, TickFileRec^.CRC, Ok);
  185.                  IF Ok<>0 THEN BadTic(s);
  186.                END;
  187.           32 : TickFileRec^.Replaces:=Rest;
  188.           41 : BEGIN
  189.                  Inc(TickFileRec^.NumPath);
  190.                  TickFileRec^.Path[TickFileRec^.NumPath]:=Rest;
  191.                END;
  192.           46 : BEGIN
  193.                  Inc(TickFileRec^.NumSeenBy);
  194.                  IF TickFileRec^.NumSeenBy>50 THEN  { CHANGE THIS SOMETIME.... }
  195.                  BEGIN
  196.                    TickFileRec^.NumSeenBy:=50;
  197.                    Move(TickFileRec^.SeenBy[2],TickFileRec^.SeenBy[1],49*SizeOf(TFidoAddress));
  198.                  END;
  199.                  IF Not GetAdressFromStr(Rest, TickFileRec^.SeenBy[TickFileRec^.NumSeenBy]) THEN
  200.                    Dec(TickFileRec^.NumSeenBy);
  201.                END;
  202.           53 : TickFileRec^.PassWord:=StUpCase(Rest);
  203.         END;
  204.       UNTIL t^.EoF OR isBad;
  205.  
  206.       Dispose(t, Done);
  207.     END ELSE
  208.     BEGIN
  209.       AddLog('!', 'File: '+TickName+' disappered??');
  210.       isBad:=True;
  211.     END;
  212.     Tick2Buffer:=NOT isBad;
  213.   END;
  214.  
  215.   PROCEDURE Add2FilesBBS;
  216.   VAR
  217.     FilesBBS, NewFilesBBS: PBufTextFile;
  218.     Added,
  219.     Found : Boolean;
  220.     s, Line: String;
  221.     FName : S12;
  222.     Offset : LongInt;
  223.   BEGIN
  224.     IF (Cfg.BBS.BBSType=btOpus170) AND FindAreaByPath(Cfg.BBS.Path, TickAreaRec^.AreaPath, Offset) THEN
  225.     BEGIN
  226. (*
  227.   FilesBBSType = RECORD
  228.     Area_Number : Word;
  229.     Name        : String[12];
  230.     Dl_Priv     : Byte;
  231.     Size        : LongInt;
  232.     Date        : Word;
  233.     Time        : Word;
  234.     AFlag       : Word;
  235.     DL_Lock     : LongInt;
  236.     Up_Date     : Word;
  237.     Up_Time     : Word;
  238.     Down_Cntr   : Word;
  239.     Descr_Len   : Word;
  240.     AltPath_Len : Byte;
  241.     Upld_by_Len : Byte;
  242.     Nxt_Key     : LongInt;
  243.     Filler      : Array[1..20] of Byte;  { Size = 64 bytes }
  244.     Description : String;
  245.     AltPath     : PathStr;
  246.     Uploaded_By : String[35];
  247.   END;
  248. *)
  249.     END ELSE
  250.     BEGIN
  251.       IF TickAreaRec^.FilesBBS='' THEN FName:='FILES.BBS' ELSE FName:=TickAreaRec^.FilesBBS;
  252.  
  253.       Line:=CPad(TickFileRec^.FileName,13)+TickFileRec^.Desc;
  254.       IF Cfg.AreaMan.InsDLCnt THEN AddDlC(Line);
  255.  
  256.       New(FilesBBS, InitCreate(AddBackSlash(TickAreaRec^.AreaPath)+FName, SOpen+ShareDenyNone, 2048));
  257.       IF FilesBBS=NIL THEN
  258.       BEGIN
  259.         AddLog('!', 'Can''t update '+FName+' with description: '+Line);
  260.       END ELSE
  261.       BEGIN
  262.         IF TickFileRec^.Replaces='' THEN
  263.         BEGIN
  264.           FilesBBS^.WriteLn(Line);
  265.           Dispose(FilesBBS, Done);
  266.         END ELSE
  267.         BEGIN
  268.           New(NewFilesBBS, Init(AddBackSlash(TickAreaRec^.AreaPath)+'TICK-TMP.$$$', SCreate, 2048));
  269.           IF NewFilesBBS=NIL THEN
  270.           BEGIN
  271.             AddLog('!', 'Can''t update '+FName+' with description: '+Line);
  272.             FilesBBS^.WriteLn(Line);
  273.             Dispose(FilesBBS, Done);
  274.           END ELSE
  275.           BEGIN
  276.             FilesBBS^.SetPos(0, PosAbs);
  277.             Found:=False; Added:=False;
  278.             WHILE NOT FilesBBS^.EoF AND (NewFilesBBS^.GetStatus=0) DO
  279.             BEGIN
  280.               FilesBBS^.ReadLn(s);
  281.               IF (Pos(' ',s)>0) AND (StUpCase(Copy(s,1,Pos(' ',s)-1))=TickFileRec^.Replaces) THEN
  282.               BEGIN
  283.                 Found:=True;
  284.                 IF Cfg.AreaMan.InsDLCnt THEN IncDLC(Line, GetDLC(s));
  285.                 IF TickFileRec^.Replaces=TickFileRec^.FileName THEN
  286.                 BEGIN
  287.                   NewFilesBBS^.WriteLn(Line);
  288.                   Added:=True;
  289.                 END;
  290.               END ELSE
  291.                 NewFilesBBS^.WriteLn(s);
  292.             END;
  293.             IF (TickFileRec^.Replaces<>TickFileRec^.FileName) OR (NOT Added) THEN NewFilesBBS^.WriteLn(Line);
  294.             IF NewFilesBBS^.GetStatus<>0 THEN
  295.             BEGIN
  296.               AddLog('!', 'Can''t update '+FName+' with description: '+Line);
  297.               Dispose(FilesBBS, Done); Dispose(NewFilesBBS, Done);
  298.               DeleteFile(AddBackSlash(TickAreaRec^.AreaPath)+'TICK-TMP.$$$');
  299.             END ELSE
  300.             BEGIN
  301.               IF Found THEN
  302.               BEGIN
  303.                 IF (TickFileRec^.Replaces<>TickFileRec^.FileName) AND
  304.                    (DeleteFile(AddBackSlash(TickAreaRec^.AreaPath)+TickFileRec^.Replaces)) THEN
  305.                   AddLog(':','Erasing '+TickFileRec^.Replaces+' replaced by '+TickFileRec^.FileName);
  306.               END;
  307.               Dispose(FilesBBS, Done); Dispose(NewFilesBBS, Done);
  308.               DeleteFile(AddBackSlash(TickAreaRec^.AreaPath)+FName);
  309.               RenameFile(AddBackSlash(TickAreaRec^.AreaPath)+'TICK-TMP.$$$', AddBackSlash(TickAreaRec^.AreaPath)+FName);
  310.             END;
  311.           END;
  312.         END;
  313.       END;
  314.     END;
  315.   END;
  316.  
  317.   FUNCTION IsDupe(CONST FName: S12; CONST Area: S20): Boolean;
  318.   VAR
  319.     S : String;
  320.     Dupe : Boolean;
  321.     DupeFile : PBufTextFile;
  322.   BEGIN
  323.     Dupe:=False;
  324.     IF Cfg.Tick.DupeDir<>'' THEN
  325.     BEGIN
  326.       New(DupeFile, Init(Cfg.Tick.DupeDir+StripDosChars(Area)+'.DUP', SOpenRead+ShareDenyNone, 2048));
  327.       IF DupeFile<>NIL THEN
  328.       BEGIN
  329.         WHILE Not DupeFile^.EoF And Not Dupe DO
  330.         BEGIN
  331.           DupeFile^.ReadLn(S);
  332.           IF Pos(' ', S)>0 THEN S:=Copy(S, 1, Pos(' ', S)-1);
  333.           IF StUpCase(FName)=Trim(S) THEN Dupe:=True;
  334.         END;
  335.         Dispose(DupeFile, Done);
  336.       END;
  337.     END;
  338.     IsDupe:=Dupe;
  339.   END;
  340.  
  341.   PROCEDURE WriteInDupeFile(CONST FName: S12; CONST Area: S20);
  342.   VAR
  343.     DupeFile : TNetFile;
  344.   BEGIN
  345.     IF Cfg.Tick.DupeDir<>'' THEN
  346.     BEGIN
  347.       IF DupeFile.Open(Cfg.Tick.DupeDir+StripDosChars(Area)+'.DUP', 1, True) THEN
  348.       BEGIN
  349.         DupeFile.Seek(DupeFile.FileSize);
  350.         DupeFile.WriteLine(StUpCase(FName));
  351.         DupeFile.Close;
  352.       END;
  353.     END;
  354.   END;
  355.  
  356.   FUNCTION MoveTick(VAR TickFile: TNetFile; CONST TickName: S12; CONST NodeStat: TNodeStat): Boolean;
  357.   VAR
  358.     TSr : SearchRec;
  359.     s : PathStr;
  360.     OldName : S12;
  361.     Success : Boolean;
  362.  
  363. (*
  364.     PROCEDURE WriteTickLetter;
  365.     VAR
  366.       tf    : PBufTextFile;
  367.       FName : PathStr;
  368.  
  369.       PROCEDURE ReadTemplate;
  370.       VAR
  371.         i : Byte;
  372.         Tpl : PBufTextFile;
  373.         S : S80;
  374.       BEGIN
  375.         FOR i:=1 TO 3 DO
  376.         BEGIN
  377.           PoPGetMem(POINTER(TickMsgPtr[i]),SizeOf(TTickMsg));
  378.           FillChar(TickMsgPtr[i]^, SizeOf(TickMsgPtr[i]^), 0);
  379.         END;
  380.         New(Tpl, Init(StartPath+PoPTemplateFileName, SOpenRead+ShareDenyNone, 2048));
  381.         i:=0;
  382.         IF Tpl<>NIL THEN
  383.         BEGIN
  384.           WHILE NOT Tpl^.EoF DO
  385.           BEGIN
  386.             Tpl^.ReadLn(S);
  387.             IF Copy(S,1,1)='/' THEN
  388.             BEGIN
  389.               IF StUpCase(Copy(s,1,9))='/TICKHEAD' THEN i:=1 ELSE
  390.                 IF StUpCase(Copy(s,1,9))='/TICKBODY' THEN i:=2 ELSE
  391.                   IF StUpCase(Copy(s,1,9))='/TICKFOOT' THEN i:=3 ELSE
  392.                     i:=0;
  393.             END ELSE
  394.               IF (i>0) And (TickMsgPtr[i]^.NumLines<10) THEN
  395.               BEGIN
  396.                 Inc(TickMsgPtr[i]^.NumLines);
  397.                 TickMsgPtr[i]^.Line[TickMsgPtr[i]^.NumLines]:=S;
  398.               END;
  399.           END;
  400.         END;
  401.         IF TickMsgPtr[2]^.NumLines=0 THEN
  402.         BEGIN
  403.           TickMsgPtr[2]^.NumLines:=2;
  404.           TickMsgPtr[2]^.Line[1]:='  $FileName ($Size) in $HumanName ';
  405.         END;
  406.         Dispose(Tpl, Done);
  407.       END;
  408.  
  409.       PROCEDURE WriteHeader;
  410.       VAR
  411.         i : Byte;
  412.         s : String;
  413.       BEGIN
  414.         IF TickMsgPtr[1]^.NumLines>0 THEN
  415.         BEGIN
  416.           FOR i:=1 TO TickMsgPtr[1]^.NumLines DO
  417.           BEGIN
  418.             s:=TickMsgPtr[1]^.Line[i];
  419.             Replace(s, '$today', TodayString('mm/dd/yy'), 0);
  420.             Replace(s, '$groupname', TickAreaRec^.GroupName, 0);
  421.             tf^.WriteLn(s);
  422.           END;
  423.         END;
  424.       END;
  425.  
  426.       PROCEDURE WriteBody;
  427.       VAR
  428.         i : Byte;
  429.         s : String;
  430.       BEGIN
  431.         IF TickMsgPtr[2]^.NumLines>0 THEN
  432.         BEGIN
  433.           FOR i:=1 TO TickMsgPtr[2]^.NumLines DO
  434.           BEGIN
  435.             s:=TickMsgPtr[2]^.Line[i];
  436.             Replace(s, '$filename', Pad(TSr.Name,12), 0);
  437.             Replace(s, '$filesize', LongIntForm('#.###', TSr.Size div 1024), 0);
  438.             Replace(s, '$desc', TickFileRec^.Desc, 0);
  439.             Replace(s, '$tickarea', TickFileRec^.Area, 0);
  440.             Replace(s, '$humanname', TickAreaRec^.HumanName, 0);
  441.             tf^.WriteLn(s);
  442.           END;
  443.         END;
  444.       END;
  445.  
  446.     BEGIN
  447.       FName:=TickAreaRec^.GroupName;
  448.       IF Length(FName)>8 THEN Insert('.',FName,9);
  449.       FName:=TickLetterPath+FName;
  450.       IF TickMsgPtr[1]=NIL THEN ReadTemplate;
  451.       New(tf, Init(FName, SOpen, 4096));
  452.       IF tf=NIL THEN
  453.       BEGIN
  454.         AddLog(':','Creating letter for group: '+TickAreaRec^.GroupName);
  455.         New(tf, Init(FName, SCreate, 4096));
  456.         WriteHeader;
  457.       END ELSE
  458.         tf^.SetPos(0, PosEnd);
  459.       WriteBody;
  460.       Dispose(tf, Done);
  461.     END;
  462. *)
  463.  
  464.     PROCEDURE RemoveFromTit(CONST FName: S12);
  465.     VAR
  466.       TitF : TTitFile;
  467.     BEGIN
  468.       IF TitF.Open(False) THEN
  469.       BEGIN
  470.         TitF.RemoveFile(FName);
  471.         TitF.Close;
  472.       END;
  473.     END;
  474.  
  475.     PROCEDURE RenameTick;
  476.     BEGIN
  477.       IF RenameFile(Cfg.Inbound[NodeStat]+TickName, ForceExtension(Cfg.Inbound[NodeStat]+TickName, 'BAD')) THEN
  478.         AddLog('*', TickName+' renamed to '+ForceExtension(TickName, 'BAD'));
  479.     END;
  480.  
  481.   BEGIN
  482.     MoveTick:=False;
  483.     Success:=False;
  484.     IF Tick2Buffer(TickName, NodeStat) THEN
  485.     BEGIN
  486.       AddLog('*','Processing: '+TickFileRec^.FileName+' in area: '+TickFileRec^.Area+' from: '+Address2Str(TickFileRec^.From));
  487.       IF FindTickArea(TickFile, TickFileRec^.Area) THEN
  488.       BEGIN
  489.         IF CheckGetFrom(TickFileRec^.From)<>0 THEN
  490.         BEGIN
  491.           IF FindNodeInfo(NodesRec,TickFileRec^.From) THEN
  492.           BEGIN
  493.             IF (TickFileRec^.Password=NodesRec.TickPassword) OR (TickFileRec^.Password='') THEN
  494.             BEGIN
  495.               FindFirst(Cfg.Inbound[NodeStat]+TickFileRec^.FileName,AnyFile,TSr);
  496.               IF (DosError<>0) AND (TickAreaRec^.CanBeRepacked) THEN
  497.               BEGIN
  498.                 s:=TickFileRec^.FileName;
  499.                 IF Pos('.',s)>0 THEN s:=Copy(s,1,Pos('.',s)-1);
  500.                 s:=s+'.*';
  501.                 FindClose(TSr);
  502.                 FindFirst(Cfg.Inbound[NodeStat]+s,AnyFile,TSr);
  503.               END;
  504.               IF DosError=0 THEN
  505.               BEGIN
  506.                 IF TickFileRec^.FileName<>TSr.Name THEN
  507.                 BEGIN
  508.                   TickFileRec^.CRC:=FileCRC(Cfg.Inbound[NodeStat]+TSr.Name);
  509.                   OldName:=TickFileRec^.FileName;
  510.                   TickFileRec^.FileName:=StUpCase(TSr.Name);
  511.                 END;
  512.                 IF (NOT TickAreaRec^.CheckCRC) OR (FileCrC(Cfg.Inbound[NodeStat]+TickFileRec^.FileName)=TickFileRec^.CRC) THEN
  513.                 BEGIN
  514.                   IF (TickFileRec^.Replaces<>'') OR NOT (TickAreaRec^.CheckDupe) OR
  515.                     NOT IsDupe(TSr.Name,TickAreaRec^.AreaName) THEN
  516.                   BEGIN
  517.                     IF ExistFile(AddBackSlash(TickAreaRec^.AreaPath)+TSr.Name) AND (TickFileRec^.Replaces='') THEN
  518.                       TickFileRec^.Replaces:=TSr.Name;
  519.                     AddLog('+','Moving '+TSr.Name+' to '+AddBackSlash(TickAreaRec^.AreaPath));
  520.                     IF CopyFile(Cfg.Inbound[NodeStat]+TSr.Name,
  521.                                 AddBackSlash(TickAreaRec^.AreaPath)+TSr.Name,False,True)=0 THEN
  522.                     BEGIN
  523.                       IF TickAreaRec^.CheckDupe THEN WriteInDupeFile(TSr.Name,TickAreaRec^.AreaName);
  524.                       RemoveFromTit(OldName);
  525.                       DeleteFile(Cfg.Inbound[NodeStat]+TickName);
  526.                       Add2FilesBBS;
  527. {---
  528.                       IF TickAreaRec^.WriteLetter AND (TickAreaRec^.AnnouncePath<>'') AND
  529.                          (TickAreaRec^.GroupName<>'') THEN
  530.                         WriteTickLetter;
  531. ---}
  532.                       MoveTick:=True;
  533.                       Success:=True;
  534.                     END ELSE
  535.                       AddLog('!','Can''t copy file to destination directory');
  536.                   END ELSE
  537.                     AddLog('!','Dupe: '+TSr.Name+' in area: '+TickFileRec^.Area) ;
  538.                 END ELSE
  539.                   AddLog('!','CRC Error: '+TSr.Name+' in area: '+TickFileRec^.Area) ;
  540.               END ELSE
  541.               BEGIN
  542.                 IF Cfg.Tick.RequestMissing THEN
  543.                 BEGIN
  544.                   IF RequestAFile(TickFileRec^.FileName, TickFileRec^.From, '') THEN
  545.                     AddLog('#', 'File not found: '+TickFileRec^.FileName+' requesting it from: '+
  546.                            Address2Str(TickFileRec^.From))
  547.                   ELSE
  548.                     AddLog('#', 'File not found: '+TickFileRec^.FileName+' HAS been requested from: '+
  549.                            Address2Str(TickFileRec^.From));
  550.                   Success:=True;
  551.                 END ELSE
  552.                   AddLog('!','File not found: '+TickFileRec^.FileName);
  553.               END;
  554.               FindClose(TSr);
  555.             END ELSE
  556.               AddLog('!','Password error');
  557.           END ELSE
  558.             AddLog('!',Address2Str(TickFileRec^.From)+' not found in Nodes Setup');
  559.         END ELSE
  560.           AddLog('!',Address2Str(TickFileRec^.From)+' is not allowed to hatch into: '+TickFileRec^.Area);
  561.       END ELSE
  562.         AddLog('!','Unknown tick area: '+TickFileRec^.Area);
  563.     END ELSE
  564.       AddLog('!','Error in tick file: '+TickName);
  565.     IF NOT Success THEN RenameTick;
  566.   END;
  567.  
  568.   PROCEDURE FindNodesToSendTo(VAR TickToTab: SendToTabType; VAR Num: Word);
  569.   VAR
  570.     TmpTab : SendToTabType;
  571.     i,j,GFNum, STNum : Byte;
  572.   BEGIN
  573.     FillChar(TickToTab, SizeOf(TickToTab), 0);
  574.     ReadSendTo(TickAreaRec^.GetFrom, TickToTab, GFNum);
  575.     i:=CheckGetFrom(TickFileRec^.From);
  576.     IF i>0 THEN
  577.     BEGIN
  578.       FOR j:=i TO GFNum-1 DO
  579.         TickToTab[j]:=TickToTab[j+1];
  580.       Dec(GFNum);
  581.     END;
  582.     ReadSendTo(TickAreaRec^.SendTo, TmpTab, STNum);
  583.     FOR i:=GFNum+1 TO GFNum+1+STNum DO
  584.       TickToTab[i]:=TmpTab[i-GFNum];
  585.     Num:=GFNum+StNum;
  586.   END;
  587.  
  588.   FUNCTION MakeTickDate: S40;
  589.   VAR
  590.     s : S40;
  591.     Hour, Min, Sec, Sec100,
  592.     Year, Month, Day, DoW : Word;
  593.   BEGIN  { (UnixDate) Sat Jan 11 12:56:57 1992 GMT }
  594.     s:=TodayString('www nnn dd yyyy');
  595.     s:=Copy(s,1,10)+CurrentTimeString(' hh:mm:ss')+Copy(s,11,5){+' GMT'};
  596.     GetDate(Year, Month, Day, DoW);
  597.     GetTime(Hour, Min, Sec, Sec100);
  598.     s:=' '+Long2Str(GetUnixDate(Year,Month,Day,Hour,Min,Sec))+' '+s;
  599.     MakeTickDate:=s;
  600.   END;
  601.  
  602.   PROCEDURE FindRightAkA(VAR Address: TFidoAddress);
  603.   VAR
  604.     i : Byte;
  605.     Found : Boolean;
  606.   BEGIN
  607.     IF (TickAreaRec^.AKAToUse>0) AND (Cfg.Addresses[TickAreaRec^.AKAToUse].Zone<>0) THEN
  608.     BEGIN
  609.       Address:=Cfg.Addresses[TickAreaRec^.AKAToUse];
  610.     END ELSE
  611.     BEGIN
  612.       i:=1; Found:=False;
  613.       REPEAT
  614.         IF (Cfg.Addresses[i].Zone<>0) And (Cfg.Addresses[i].Zone=Address.Zone) THEN
  615.         BEGIN
  616.           Address:=Cfg.Addresses[i];
  617.           Found:=True;
  618.         END;
  619.         Inc(i);
  620.       UNTIL (i>MaxAddresses) OR (Found);
  621.       IF NOT Found THEN Address:=Cfg.Addresses[Cfg.MainAdrNum];
  622.     END;
  623.   END;
  624.  
  625.   FUNCTION NodeInSeenBy(CONST Adr: TFidoAddress): Boolean;
  626.   VAR
  627.     i : Byte;
  628.   BEGIN
  629.     NodeInSeenBy:=False;
  630.     FOR i:=1 TO TickFileRec^.NumSeenBy DO
  631.       IF CmpAdr(Adr, TickFileRec^.SeenBy[i]) THEN
  632.       BEGIN
  633.         NodeInSeenBy:=True;
  634.         Break;
  635.       END;
  636.   END;
  637.  
  638.   PROCEDURE SendTick(CONST UPath: PathStr);
  639.   VAR
  640.     SendTickFile : PBufTextFile;
  641.     Num,i,j: Word;
  642.     Tp,PTName,s : PathStr;
  643.     FL: Char;
  644.     WasThere: Boolean;
  645.     Pk : Byte;
  646.     TmpSendTo : SendToType;
  647.     TickToTab : SendToTabType;
  648.   BEGIN
  649.     FindNodesToSendTo(TickToTab, Num);
  650.     IF Num>0 THEN
  651.     BEGIN
  652.       WriteSendTo(TickToTab,TmpSendTo,Num);
  653.       FOR i:=1 TO 2 DO
  654.       BEGIN
  655.         IF TmpSendTo[i]<>'' THEN AddLog('+','Sending '+JustFileName(TickFileRec^.FileName)+' to '+TmpSendTo[i]);
  656.       END;
  657.       IF Cfg.Tick.HoldDir='' THEN tp:=Cfg.Outbound+'.TIC\' ELSE tp:=Cfg.Tick.HoldDir;
  658.       IF NOT ChkDir(tp) THEN MakeFullDir(tp);
  659.       FindRightAkA(TickFileRec^.From);
  660.       FOR i:=1 TO Num DO
  661.       BEGIN
  662.         IF NOT NodeInSeenBy(TickToTab[i]) THEN
  663.         BEGIN
  664.           FindNodeInfo(NodesRec,TickToTab[i]);
  665.           REPEAT
  666.             s:=tp+'TK'+Copy(InventPktName,3,6)+'.TIC';
  667.           UNTIL Not ExistFile(s);
  668.           New(SendTickFile, Init(s, SCreate, 4096));
  669.           IF SendTickFile<>NIL THEN
  670.           BEGIN
  671.             SendTickFile^.WriteLn('Area '+TickFileRec^.Area);
  672.             SendTickFile^.WriteLn('Origin '+TickFileRec^.Origin);
  673.             SendTickFile^.WriteLn('From '+Adr2Str(TickFileRec^.From));
  674.             SendTickFile^.WriteLn('File '+TickFileRec^.FileName);
  675.             IF TickFileRec^.Replaces<>'' THEN
  676.               SendTickFile^.WriteLn('Replaces '+TickFileRec^.Replaces);
  677.             SendTickFile^.WriteLn('Desc '+TickFileRec^.Desc);
  678.             SendTickFile^.WriteLn('CRC '+HexL(TickFileRec^.CRC));
  679.             SendTickFile^.WriteLn('Created by Portal of Power v'+ver+' (C) Copyright 1989-95 by The Portal Team');
  680.             FOR j:=1 TO TickFileRec^.NumPath DO
  681.               SendTickFile^.WriteLn('Path '+TickFileRec^.Path[j]) ;
  682.             SendTickFile^.WriteLn('Path '+Adr2Str(TickFileRec^.From)+MakeTickDate);
  683.             FOR j:=1 TO TickFileRec^.NumSeenBy DO
  684.               SendTickFile^.WriteLn('Seenby '+Adr2Str(TickFileRec^.SeenBy[j])) ;
  685.             FOR j:=1 TO Num DO
  686.               SendTickFile^.WriteLn('Seenby '+Adr2Str(TickToTab[j])) ;
  687.             SendTickFile^.WriteLn('Seenby '+Adr2Str(TickFileRec^.From)) ;
  688.             IF NodesRec.TickPassword<>'' THEN
  689.               SendTickFile^.WriteLn('PW '+NodesRec.TickPassword);
  690.             Dispose(SendTickFile, Done);
  691.             CASE NodesRec.Flavor OF
  692.               'N' : FL:='F';
  693.               'C',
  694.               'I',
  695.               'D' : FL:=NodesRec.Flavor;
  696.               ELSE FL:='H';
  697.             END;
  698.             WITH TickToTab[i] DO
  699.             BEGIN
  700.               IF UPath='' THEN
  701.                 SendAFile(AddBackSlash(TickAreaRec^.AreaPath)+TickFileRec^.FileName, TickToTab[i], FL, STNothing)
  702.               ELSE
  703.                 SendAFile(AddBackSlash(UPath)+TickFileRec^.FileName, TickToTab[i], FL, STNothing);
  704.               IF NodesRec.PackTick THEN
  705.               BEGIN
  706.                 PTName:=HoldFileName(TickToTab[i],True)+'PTF' ;
  707.                 WasThere:=ExistFile(PTName);
  708.                 IF NodesRec.PackerType=0 THEN Pk:=1 ELSE Pk:=NodesRec.PackerType;
  709.                 IF ArcCommand(Pk,1,PtName,s) THEN
  710.                 BEGIN
  711.                   DeleteFile(s);
  712.                   IF Not WasThere THEN SendAFile(PTName,TickToTab[i],FL,STDelete);
  713.                 END ELSE
  714.                   SendAFile(s, TickToTab[i], FL,STDelete);
  715.               END ELSE
  716.                 SendAFile(s, TickToTab[i], FL, STDelete);
  717.             END;
  718.           END ELSE
  719.             AddLog('!','Not enough memory to create: '+s)
  720.         END ELSE
  721.           AddLog('#','Skipping '+Address2Str(TickToTab[i])+' - is in seenby');
  722.       END;
  723.     END;
  724.   END;
  725.  
  726.   PROCEDURE UnPackTicks(CONST NodeStat: TNodeStat);
  727.   VAR
  728.     Sr : SearchRec;
  729.     s : PathStr;
  730.   BEGIN
  731.     FindFirst(Cfg.Inbound[NodeStat]+'*.PTF',AnyFile,Sr);
  732.     IF DosError=0 THEN AddLog(' ','Unpacking packed tick files');
  733.     WHILE DosError=0 DO
  734.     BEGIN
  735.       GetDir(0,s); ChangeDir(Cfg.Inbound[NodeStat]);
  736.       IF ArcCommand(ArcType(sr.Name),2,sr.name,'*.TIC') THEN DeleteFile(Sr.Name);
  737.       ChangeDir(s);
  738.       FindNext(Sr);
  739.     END;
  740.     FindClose(Sr);
  741.   END;
  742.  
  743.   PROCEDURE ProcessTicks;
  744.   VAR
  745.     Sr       : SearchRec;
  746.     NodeStat : TNodeStat;
  747.     TickFile : TNetFile;
  748.     TmpAdr   : TFidoAddress;
  749.   BEGIN
  750. {$IFNDEF PoPLite}
  751.     IF Cfg.TaskType=2 THEN
  752.     BEGIN
  753.       RequestFunction(fsProcessTicks);
  754.       EXIT;
  755.     END;
  756.     FillChar(TmpAdr, SizeOf(TmpAdr), 0);
  757.     IF Not SetInterCom(ICTick, TmpAdr, False) THEN Exit;
  758.     IF TickFile.Open(StartPath+PoPTickFileName, SizeOf(TTickArea),False) THEN
  759.     BEGIN
  760.       AddLog('+','Searching for Tick files');
  761. {
  762.       TickLetterPath:=StartPath+'TICKMSG.'+HexW(Cfg.TaskNumber)+'\';
  763.       MakeFullDir(TickLetterPath);
  764. }
  765.       New(TickFileRec);
  766.       New(TickAreaRec);
  767.       IF (TickFileRec<>NIL) AND (TickAreaRec<>NIL) THEN
  768.       BEGIN
  769.         FOR NodeStat:=nsUnKnown TO nsPassword DO
  770.         BEGIN
  771.           IF (Cfg.InboundToDo[NodeStat] AND itd_Tick)<>0 THEN
  772.           BEGIN
  773.             UnpackTicks(NodeStat);
  774.             FindFirst(Cfg.Inbound[NodeStat]+'*.TIC',AnyFile,Sr);
  775.             IF (DosError=0) AND (Cfg.Tick.BeforeMoving<>'') THEN RunCmd(Cfg.Tick.BeforeMoving, Cfg.Inbound[NodeStat]);
  776.             WHILE DosError=0 DO
  777.             BEGIN
  778.               AddLog(':','Processing: '+Sr.Name);
  779.               IF MoveTick(TickFile, Sr.Name, NodeStat) THEN SendTick('');
  780.               FindNext(Sr);
  781.             END;
  782.             FindClose(Sr);
  783.           END;
  784.         END;
  785.       END ELSE
  786.         AddLog('!','Not enough memory to process tick files');
  787.       IF TickAreaRec<>NIL THEN Dispose(TickAreaRec);
  788.       IF TickFileRec<>NIL THEN Dispose(TickFileRec);
  789.       { Txt2Messages }
  790. {
  791.       RmDir(Copy(TickLetterPath,1,Length(TickLetterPath)-1));
  792. }
  793.       TickFile.Close;
  794.       AddLog('+','Tick processing done');
  795.     END;
  796. {$ENDIF}
  797.   END;
  798.  
  799.   PROCEDURE Hatch(CONST FName: PathStr; CONST Description: STRING);
  800.   VAR
  801.     TickFile : TNetFile;
  802.     i        : Byte;
  803.     ok       : Boolean;
  804.  
  805.     FUNCTION FindTickArea: Boolean;
  806.     VAR
  807.       b  : Boolean;
  808.       jp : PathStr;
  809.     BEGIN
  810.       b:=False;
  811.       jp:=StUpCase(AddBackSlash(JustPathName(FName)));
  812.       TickFile.SEEK(0);
  813.       WHILE NOT TickFile.EoF AND (NOT b) DO
  814.       BEGIN
  815.         TickFile.Read(TickAreaRec^,NoKeep,Wait);
  816.         IF jp=AddBackSlash(TickAreaRec^.AreaPath) THEN b:=True;
  817.       END;
  818.       FindTickArea:=b;
  819.     END;
  820.  
  821.     PROCEDURE PickTicks;
  822.     VAR
  823.       pl : TTickAreaPickList;
  824.       OldTopic : Word;
  825.     BEGIN
  826.       pl.Init(TickFile);
  827.       IF ok THEN
  828.       BEGIN
  829.         pl.SetInitialChoice(TickFile.FILEPOS);
  830.         ok:=False;
  831.       END;
  832.       OldTopic:=Topic;
  833.       Topic:=2002;
  834.       pl.Process;
  835.       pl.Erase;
  836.       Topic:=OldTopic;
  837.       IF pl.GetLastCommand<>ccQuit THEN
  838.       BEGIN
  839.         TickFile.GetRec(TickAreaRec^,pl.GetLastChoice-1,NoKeep,Wait);
  840.         ok:=True;
  841.       END;
  842.       pl.Done;
  843.     END;
  844.  
  845.   BEGIN
  846.     IF TickFile.Open(StartPath+PoPTickFileName, SizeOf(TTickArea), False) THEN
  847.     BEGIN
  848.       New(TickFileRec);
  849.       New(TickAreaRec);
  850.       IF (TickFileRec<>NIL) AND (TickAreaRec<>NIL) THEN
  851.       BEGIN
  852.         FILLCHAR(TickFileRec^,SizeOf(TickFileRec^),0);
  853.         ok:=FindTickArea;
  854.         PickTicks;
  855.         IF ok THEN
  856.         BEGIN
  857.           WITH TickFileRec^ DO
  858.           BEGIN
  859.             FileName:=StUpCase(JustFileName(FName));
  860.             Replaces:=FileName;
  861.             InputString(21, 7, 12, 12, 2, 'Hatch file', 'Replaces: ', Replaces);
  862.             Area:=TickAreaRec^.AreaName;
  863.  
  864.             Desc:='A '+Trim(Description);
  865.             DelDlC(Desc);
  866.             Delete(Desc,1,13);
  867.  
  868.             IF (Cfg.BBS.BBSType=btMax) AND (Length(Desc)>0) AND (Copy(Desc,1,1)='/') THEN
  869.             BEGIN
  870.               i:=Pos(' ', Desc);
  871.               IF i>0 THEN Delete(Desc, 1, i) ELSE Desc:='';
  872.             END;
  873.  
  874.             Crc:=FileCRC(FName);
  875.             NumSeenBy:=0;
  876.             IF (TickAreaRec^.AkaToUse>0) AND (Cfg.Addresses[TickAreaRec^.AkaToUse].Zone<>0) THEN
  877.             BEGIN
  878.               Origin:=Adr2Str(Cfg.Addresses[TickAreaRec^.AkaToUse]);
  879.               From:=Cfg.Addresses[TickAreaRec^.AkaToUse];
  880.             END ELSE
  881.             BEGIN
  882.               Origin:=Adr2Str(Cfg.Addresses[Cfg.MainAdrNum]);
  883.               From:=Cfg.Addresses[Cfg.MainAdrNum];
  884.             END;
  885.             AddLog(':', 'Hatching '+FileName+': "'+Desc+'" in area '+Area);
  886.           END;
  887.           SendTick(JustPathName(FName));
  888.         END;
  889.       END ELSE
  890.         AddLog('!' ,'Not enough memory to hatch files');
  891.       IF TickAreaRec<>NIL THEN Dispose(TickAreaRec);
  892.       IF TickFileRec<>NIL THEN Dispose(TickFileRec);
  893.       TickFile.Close;
  894.     END;
  895.   END;
  896.  
  897. END.
  898.